import pygame
import os
from math import floor, ceil
from random import randint

pygame.init()
pygame.mixer.init()

WIDTH, HEIGHT = 900, 600
MouseX, MouseY = 0, 0
clock = pygame.time.Clock()
FGH = "---------------------"
FPS = 60
inputting = False
command = ""

# image loads
player_head_img = os.path.join("./img/player_head.png")
block_img = os.path.join("./img/stone.png")
frame_img = os.path.join("./img/frame.png")

# sound loads
Place = lambda: pygame.mixer.Sound(f"./audio/place/Stone_dig{randint(1, 4)}.ogg")
Break = lambda: pygame.mixer.Sound(f"./audio/break/Stone_dig{randint(1, 4)}.ogg")
Step = lambda: pygame.mixer.Sound(f"./audio/step/Stone_step{randint(1, 4)}.ogg")

print(FGH)
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Minecraft*  Rungame beta v1.2")
pygame.display.set_icon(pygame.image.load(player_head_img))
screen.fill("#B0C4DE")

Blocks = [
    [0 for i in range(18)] for j in range(12)
]

BlocksRect = []

all_sprites = pygame.sprite.Group()


def SoundPlay(Sound):
    Sound.play()


def RectNext(Rect1, Rect2):
    if (
            Rect1.right == Rect2.left
            and Rect1.top < Rect2.bottom
            and Rect1.bottom > Rect2.top
    ):
        return True
    if (
            Rect1.left == Rect2.right
            and Rect1.top < Rect2.bottom
            and Rect1.bottom > Rect2.top
    ):
        return True
    if (
            Rect1.bottom == Rect2.top
            and Rect1.left < Rect2.right
            and Rect1.right > Rect2.left
    ):
        return True
    if (
            Rect1.top == Rect2.bottom
            and Rect1.left < Rect2.right
            and Rect1.right > Rect2.left
    ):
        return True
    return False


class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.image.load(player_head_img).convert()
        self.rect = self.image.get_rect()
        self.rect.center = (WIDTH / 2, HEIGHT / 2)
        self.PosX = self.rect.x / 50
        self.PosY = self.rect.y / 50
        self.y_speed = 0
        self.speed = 8
        self.tick = 0
        self.ticks = floor(self.speed * 2.5)
        self.LastX = self.LastY = 0
        self.jumping = False
        self.LastJumping = False
        self.suspension = True
        self.LastSuspension = True
        self.resurx = 9
        self.resury = 6
        self.ColliderUp = 0
        self.ColliderDown = 0
        self.ColliderLeft = 0
        self.ColliderRight = 0
        self.RectX = WIDTH / 2
        self.RectY = HEIGHT / 2
        self.RollX = self.RectX
        self.RollY = self.RectY

    def Contact_edge(self):
        for block in BlocksRect:
            if self.rect.colliderect(block):
                return True
        return False

    def positioning(self):
        self.rect.center = (self.RectX - self.RollX + WIDTH / 2, self.RectY - self.RollY + HEIGHT / 2)

    def horizontal(self, x_speed):
        self.RectX += x_speed
        self.positioning()
        while self.Contact_edge():
            if x_speed > 0:
                self.RectX -= 1
            else:
                self.RectX += 1
            self.positioning()

    def vertical(self, y_speed):
        self.RectY += y_speed
        self.positioning()
        while self.Contact_edge():
            if y_speed > 0:
                self.RectY -= 1
                self.jumping = False
            else:
                self.RectY += 1
            self.positioning()
            self.y_speed = 0

    def noise(self):
        self.tick += 1
        for block in BlocksRect:
            if RectNext(self.rect, block) and self.rect.bottom == block.top:
                if self.rect.x != self.LastX:
                    if self.tick == self.ticks:
                        SoundPlay(Step())

    def IsSuspension(self):
        for block in BlocksRect:
            if RectNext(self.rect, block) and self.rect.bottom == block.top:
                return False
        return True

    def SetPos(self, pos_x, pos_y):
        self.RectX = pos_x * 50 - 25
        self.RectY = pos_y * 50 - 25
        self.y_speed = 0

    def InformationOutput(self):
        print()
        print("Block:", round(self.PosX), round(self.PosY))
        print("X:", self.PosX, " ", "Y:", self.PosY)
        print("Collider:", " ", "left", self.ColliderLeft, "right", self.ColliderRight, "up", self.ColliderUp, "down",
              self.ColliderDown)
        print("Jumping:", self.jumping)
        print("Suspensiton:", self.suspension)
        print(FGH)

    def update(self):
        # data update
        self.suspension = self.IsSuspension()
        self.PosX = self.RectX / 50
        self.PosY = self.RectY / 50
        self.ColliderLeft = floor(self.PosX)
        self.ColliderRight = ceil(self.PosX)
        self.ColliderUp = floor(self.PosY)
        self.ColliderDown = ceil(self.PosY)

        if self.RectY > HEIGHT + 300:
            self.SetPos(self.resurx, self.resury)

        # keys check
        key_pressed = pygame.key.get_pressed()
        if key_pressed[pygame.K_a]:
            self.horizontal(-self.speed)
            self.noise()
        elif key_pressed[pygame.K_d]:
            self.horizontal(self.speed)
            self.noise()
        else:
            self.tick = self.ticks

        if key_pressed[pygame.K_w]:
            if not self.suspension:
                flag = True
                for block in BlocksRect:
                    if RectNext(block, self.rect):
                        if self.rect.top == block.bottom:
                            flag = False
                            break
                if flag:
                    self.y_speed = -19
                    self.jumping = True

        self.y_speed += 1
        self.vertical(self.y_speed)
        self.RollX = self.RectX
        self.RollY = self.RectY
        self.positioning()
        if not self.suspension and self.LastSuspension:
            SoundPlay(Step())
        elif self.LastY > self.RectY:
            for block in BlocksRect:
                if RectNext(self.rect, block) and self.rect.bottom == block.top:
                    SoundPlay(Step())

        if self.tick >= self.ticks:
            self.tick = 0
        self.LastX = self.RectX
        self.LastY = self.RectY
        self.LastJumping = self.jumping
        self.LastSuspension = self.suspension


player: Player = Player()

all_sprites.add(player)


class Block(pygame.sprite.Sprite):
    def __init__(self, y, x):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(block_img).convert()
        self.XPos = x
        self.YPos = y
        self.RectCenter = (self.YPos * 50, self.XPos * 50)
        self.RectX = self.RectCenter[0]
        self.RectY = self.RectCenter[1]
        self.rect = self.image.get_rect()
        self.rect.centerx = self.YPos * 50 - player.RollX + WIDTH / 2
        self.rect.centery = self.XPos * 50 - player.RollY + HEIGHT / 2
        if self.rect.colliderect(player.rect):
            self.kill()
            return
        Blocks[self.XPos][self.YPos] = 1
        all_sprites.add(self)
        BlocksRect.append(self.rect)

    def positioning(self):
        self.rect.centerx = self.YPos * 50 - player.RollX + WIDTH / 2
        self.rect.centery = self.XPos * 50 - player.RollY + HEIGHT / 2

    def update(self):
        self.positioning()
        if Blocks[self.XPos][self.YPos] == 0:
            Blocks[self.XPos][self.YPos] = 0
            all_sprites.remove(self)
            BlocksRect.remove(self)
            self.kill()
            return


# class Frame(pygame.sprite.Sprite):
#     def __init__(self):
#         pygame.sprite.Sprite.__init__(self)
#         self.image = pygame.image.load(frame_img).convert()
#         self.image.set_colorkey("white")
#         self.rect = self.image.get_rect()
#         self.RectX = floor(MouseX / 50)
#         self.RectY = floor(MouseY / 50)
#
#     def update(self):
#         # data update
#         self.RectX = (floor(MouseX / 50) + floor(player.RollX / 50)) * 50 - WIDTH / 2
#         self.RectY = (floor(MouseY / 50) + floor(player.RectY / 50)) * 50 - HEIGHT / 2
#         self.rect.x = self.RectX
#         self.rect.y = self.RectY


def BuildBlock(XPos, YPos):
    global Blocks
    Block(XPos, YPos)


def RemoveBlock(XPos, YPos):
    global Blocks
    Blocks[YPos][XPos] = 0


def RunCommand(command):
    if len(command) == 0:
        return
    if command[0] == "gamerule":
        rule = command[1]
        if rule == "PlayerResur":
            xx = int(command[2])
            yy = int(command[3])
            player.resurx = xx
            player.resury = yy
        elif rule == "PlayerSpeed":
            spd = int(command[2])
            player.speed = spd
    elif command[0] == "setblock":
        block = command[3]
        xx = int(command[1])
        yy = int(command[2])
        if block == "stone":
            BuildBlock(xx, yy)
        elif block == "air":
            RemoveBlock(xx, yy)
    elif command[0] == "fill":
        x1 = int(command[1])
        y1 = int(command[2])
        x2 = int(command[3])
        y2 = int(command[4])
        block = command[5]
        for i in range(x1, x2 + 1):
            for j in range(y1, y2 + 1):
                if block == "stone":
                    BuildBlock(i, j)
                elif block == "air":
                    RemoveBlock(i, j)


for i in range(12):
    for j in range(18):
        if Blocks[i][j] == 1:
            BuildBlock(i, j)
RunCommand(["fill", "0", "11", "17", "11", "stone"])

# frame = pygame.sprite.Group()
# frame_sprite = Frame()
# frame.add(frame_sprite)
running = True
while running:
    clock.tick(FPS)
    MouseX, MouseY = pygame.mouse.get_pos()
    events = pygame.event.get()
    keys = pygame.key.get_pressed()
    for event in events:
        if event.type == pygame.QUIT:
            running = False
            break
        # elif event.type == pygame.MOUSEBUTTONDOWN:
        #     MousePressed = pygame.mouse.get_pressed()
        #     if 0 <= MouseX <= WIDTH and 0 <= MouseY <= HEIGHT:
        #         PosX = (floor(MouseX / 50) + floor(player.RollX / 50)) - int(WIDTH / 50 / 2)
        #         PosY = (floor(MouseY / 50) + floor(player.RectY / 50)) - int(HEIGHT / 50 / 2)
        #         print(PosX, PosY)
        #         if Blocks[PosY][PosX] == 0 and MousePressed[2]:
        #             if not ((PosX == player.ColliderLeft and PosY == player.ColliderUp) or \
        #                     (PosX == player.ColliderRight and PosY == player.ColliderUp) or \
        #                     (PosX == player.ColliderLeft and PosY == player.ColliderDown) or \
        #                     (PosX == player.ColliderRight and PosY == player.ColliderDown)):
        #                 BuildBlock(PosY, PosX)
        #                 SoundPlay(Place())
        #         elif Blocks[PosY][PosX] == 1 and MousePressed[0]:
        #             RemoveBlock(PosY, PosX)
        #             SoundPlay(Break())
        elif event.type == pygame.KEYDOWN:
            if keys[pygame.K_F3]:
                player.InformationOutput()
            if keys[pygame.K_SLASH]:
                command = input("/")
                RunCommand(command.split())
            if keys[pygame.K_ESCAPE]:
                running = False
                break

    screen.fill("#B0C4DE")

    all_sprites.draw(screen)
    all_sprites.update()
    # frame.draw(screen)
    # frame.update()

    pygame.display.update()

pygame.quit()
